package com.simplesoftwares.rebind;

import static com.simplesoftwares.client.library.helperconstants.FormTypes.DATETEXTCELL;
import static com.simplesoftwares.client.library.helperconstants.FormTypes.EDITTEXTCELL;
import static com.simplesoftwares.client.library.helperconstants.FormTypes.NUMBERTEXTCELL;
import static com.simplesoftwares.client.library.helperconstants.FormTypes.TEXTCOLUM;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;

import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.user.rebind.SourceWriter;
import com.simplesoftwares.client.library.appstructure.SuperTable;
import com.simplesoftwares.rebind.annatonations.TableAnnotation;
import com.simplesoftwares.rebind.columnwriters.ColumnGenerator;


/**
 * Contains Logic for generation of Concrete Implementation of {@link SuperTable}
 * The input data for generation comes from where {@link TableAnnotation}
 * Common work flow for creation of this generator is 
 * <code>
 * abstract class MyTable extends  SuperTable<Customer>{}
 * MyTable custTable=Gwt.create(MyTable.class)
 * {@link TableAnnotation} will come from Customer. Replaceable type will be MyTable
 * </code>
 * 
 */
public class TableGenerators extends SuperGenerator
{



	/** stores entity field  annatonations and corresponding {@link JField}  */
	protected Vector<AnnotatnedFields>annotatedFields;



	public TableGenerators()
	{
		super();
	}

	/**
	 * generate Apply Style method
	 * 
	 */

	private void generateApplyStyle() 
	{
		sWriter.println("@Override");
		sWriter.println("public void applyStyle()");
		sWriter.println("{");
		sWriter.println("}");

	}

	/**
	 * generate setEnable method
	 * 
	 */
	private void generateSetEnabled() 
	{
		sWriter.println("@Override");
		sWriter.println("public void setEnable(boolean state)");
		sWriter.println("{");
		sWriter.println("}");

	}



	/**
	 * generate filed updater method
	 * 
	 */
	protected void generatesetFieldUpdater()
	{
		sWriter.println("@Override public void addFieldUpdater() {");
		sWriter.println("}");
	}

	/**
	 * generates column sorting method
	 */
	protected void generatesetColumnSorting()
	{

		sWriter.println(" public void addColumnSorting(){");
		for(AnnotatnedFields temp:annotatedFields)
		{
			if(temp.tableAnnotation.isSortable()==true)
				sWriter.println("addSorting"+temp.method.getName()+"();");
		}
		sWriter.println("}");
	}

	/**
	 * generates method generate Key Provider
	 */
	protected void generatekeyProvider()
	{	
		String entityName=entityClaasType.getSimpleSourceName();
		sWriter.println("@Override");
		sWriter.println("protected void initializekeyprovider() {");
		sWriter.println("keyProvider= new ProvidesKey<"+entityName+">()");
		sWriter.println("{");
		sWriter.println("@Override");
		sWriter.println("public Object getKey("+entityName+" "+"item)");
		sWriter.println("{");
		sWriter.println("if(item==null)");
		sWriter.println("{");
		sWriter.println("return null;");
		sWriter.println("}");
		sWriter.println("else");
		sWriter.println("return item.getId();");
		sWriter.println("}");
		sWriter.println("};");
		sWriter.println("}");

	}

	/**
	 *generates method createTable
	 */
	protected void generatecreateTable()
	{

		//AnnotanedField needs to sorted on column number. CreateTable maintains order of column addition due to this
		
		Collections.sort(this.annotatedFields,new Comparator<AnnotatnedFields>() {
			@Override
			public int compare(AnnotatnedFields o1, AnnotatnedFields o2) {
				if(o1!=null&&o2!=null)
				{
					int colno1=o1.tableAnnotation.colNo();
					int colno2=o2.tableAnnotation.colNo();
					if(colno1>colno2)
						return 1;
					if(colno1<colno2)
						return -1;
					else
						return 0;
				}
				return 0;
			}
		});
		
		
		sWriter.println("@Override public void createTable() {");
		for(AnnotatnedFields fields:this.annotatedFields)
		{
			sWriter.println("addColumn"+fields.method.getName()+"();");
			logger.log(logger.ALL,fields.method.getName());

			
		}
		;
		sWriter.println("}");


	}

	/**
	 * @author Pradnya
	 * Maintains the Data Structure Field and corresponding {@link TableAnnotation}
	 */
	public static class AnnotatnedFields
	{
		/*
		 * Method corresponding to entity
		 */
		public JMethod method;
		

		/*
		 * Reading the Annotation on Fields
		 */
		public TableAnnotation tableAnnotation;
	}
	/**
	 * The method generates the Code which apply sorting on colums
	 * @param writer sourcewriter to write code.
	 * @param tableAnno annatonated field corresponding to tableAnnatonation
	 */

	public void generateColumnSorter(SourceWriter writer, AnnotatnedFields tableAnno)
	{
		//Name of field
		if(tableAnno.tableAnnotation.isSortable()==true)
		{
			String fieldName =tableAnno.method.getName();
			//entity name
			String entityName=entityClaasType.getSimpleSourceName();
			//datatype of field
			String datatype=tableAnno.method.getReturnType().getSimpleSourceName();
	
			writer.println("protected void addSorting"+fieldName+"()");
			writer.println("{");
			//list handler
			writer.println("List<"+entityName+">"+" "+"list=getDataprovider().getList();");
	
			writer.println("columnSort=new ListHandler<"+entityName+">(list);");
			writer.println("columnSort.setComparator("+fieldName+"Column, new Comparator<"+entityName+">()");
			writer.println("{");
			writer.println("@Override");
			writer.println("public int compare("+entityName+" "+"e1,"+entityName+" "+"e2)");
			writer.println("{");
			writer.println("if(e1!=null && e2!=null)");
			writer.println("{");
	
			//checking datatype here to manage the code inside compare method
			if(datatype.contains("String") || datatype.contains("Date"))
			{
				writer.println("if( e1."+fieldName+"()!=null && e2."+fieldName+"()!=null){");
	
				writer.println("return e1."+fieldName+"().compareTo(e2."+fieldName+"());}");
	
				writer.println("}");
				writer.println("else{");
				writer.println("return 0;}");
				writer.println("return 0;");
			}
			else if(datatype.contains("int")||datatype.contains("double")||datatype.contains("long")
					||datatype.contains("Integer")||datatype.contains("Double")||datatype.contains("Long")
					)
			{
				writer.println("if(e1."+fieldName+"()== e2."+fieldName+"()){");
				writer.println("return 0;}");
				writer.println("if(e1."+fieldName+"()> e2."+fieldName+"()){");
				writer.println("return 1;}");
				writer.println("else{");
				writer.println("return -1;}");
	
				writer.println("}");
				writer.println("else{");
				writer.println("return 0;}");
	
	
			}
			
			else if(datatype.contains("boolean")||datatype.contains("Boolean"))
			{
				writer.println("if(e1."+fieldName+"()== e2."+fieldName+"()){");
				writer.println("return 0;}");
				writer.println("else{");
				writer.println("return -1;}");
	
				writer.println("}");
				writer.println("else{");
				writer.println("return 0;}");
			}
	
			writer.println("}");
			writer.println("});");
			writer.println("table.addColumnSortHandler(columnSort);");
			writer.println("}");
		}

	}

/**
 * Reads  the annatonated field and initializes the annatonated field vector. 
 */

	@Override
	protected void readAnnotatedFields() 
	{
		annotatedFields=new Vector<AnnotatnedFields>();
		//Get fields array corresponding to this class
		ArrayList<JMethod>fieldarray= new ArrayList<JMethod>();
		fieldarray=this.getAllMethod(entityClaasType, fieldarray);
		//Get fields array corresponding 
		//logger.log(logger.ERROR,"Size of Field "+fieldarray.size());
		for(int i=0;i<fieldarray.size();i++)
		{
			TableAnnotation ano=fieldarray.get(i).getAnnotation(TableAnnotation.class);
			//logger.log(logger.ERROR,"Field is-- "+fieldarray.get(i).getName());
			if(ano!=null)
			{
				AnnotatnedFields  temp= new AnnotatnedFields();

				temp.method=fieldarray.get(i);
				temp.tableAnnotation=ano;
				annotatedFields.add(temp);
				

			}	
		}

	}
	/**
	 * Generates the variable declaration of columns
	 */

	@Override
	protected void generateVariableDeclaration() 
	{

		// Read the annotatedFields.
		logger.log(logger.INFO,"Name of source writer "+sWriter);

		for(AnnotatnedFields temp:this.annotatedFields)
		{

			String entityName=entityClaasType.getSimpleSourceName();

			String columnType=temp.tableAnnotation.ColType();
			//depending of the column type write appropriate variable declaration

			if(columnType.equals(TEXTCOLUM))
				sWriter.println("TextColumn<"+entityName+">"+" "+temp.method.getName()+"Column;");

			if(columnType.equals(EDITTEXTCELL))
				sWriter.println("Column<"+entityName+",String>"+" "+temp.method.getName()+"Column;");

			if(columnType.equals(NUMBERTEXTCELL))
				sWriter.println("Column<"+entityName+",Number>"+" "+temp.method.getName()+"Column;");

			if(columnType.equals(DATETEXTCELL))
				sWriter.println("Column<"+entityName+",Date>"+" "+temp.method.getName()+"Column;");
		}	



	}
	/**
	 * 
	 */

	@Override
	protected void generateclassBody() 
	{
		generatecreateTable();
		//Create Key Provider
		generatekeyProvider();
		//Create apply style;

		generateSetEnabled();
		//Genrate column sorting
		generateApplyStyle();
		//genrate setEditable
		generatesetColumnSorting();
		//genrate actual sorting

		//genrate field updater
		this.generatesetFieldUpdater();
		
		//Read annotaed fields
		for(AnnotatnedFields temp:this.annotatedFields)
		{
			this.generateColumnSorter(sWriter, temp);
			
			ColumnGenerator gen=ColumnGeneratorFactory.getColumnGenerator(temp.tableAnnotation.ColType());
			gen.createColumn(sWriter, entityClaasType, temp);
			gen.createFieldUpdater(sWriter, entityClaasType, temp);
			
		}
	}

	@Override
	protected void generateVariableInitialization()
	{
	

	}

	@Override
	protected void generateImports() 
	{
		imports=new ArrayList<String>();
		imports.add("com.google.gwt.user.cellview.client.TextColumn");
		imports.add("com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler");
		imports.add("com.google.gwt.view.client.ProvidesKey");
		imports.add("java.util.Comparator");
		imports.add("com.simplesoftwares.client.library.appstructure.SuperTable");
		imports.add("com.google.gwt.cell.client.FieldUpdater");
		imports.add("java.util.List");
		imports.add("java.util.Date");
		imports.add("com.google.gwt.user.cellview.client.Column");
		imports.add("com.google.gwt.cell.client.EditTextCell");
		imports.add(" com.google.gwt.cell.client.NumberCell");
		imports.add("com.google.gwt.i18n.client.DateTimeFormat");
		imports.add("com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat");
		imports.add(" com.google.gwt.cell.client.DatePickerCell");
		imports.add(entityClaasType.getQualifiedSourceName());
		imports.add(replasableClassType.getQualifiedSourceName());
		imports.add("com.slicktechnologies.client.utility.Screen");

	}
	
	protected void generategetVarRef()
	{
		sWriter.println("public Object getVarRef(String varName)");
		sWriter.println("{");
		for(AnnotatnedFields anno:this.annotatedFields)
		{
			sWriter.println("if(varName.equals("+cots+anno.method.getName()+"Column"+cots+"))");
			    sWriter.println("return this."+anno.method.getName()+"Column;");
		}
		sWriter.println(" return null ;");
		
		sWriter.println("}");
	}
	



}
